#include "laby.h"

void PrintPixel(int i, int j, int pixelsize){
    int k;
    for(k=0 ; k<pixelsize*pixelsize ; k++){
        putpixel(i*pixelsize+k/pixelsize,j*pixelsize+k%pixelsize);
    }
}

int getcolor(unsigned char r, unsigned char g, unsigned char b){
    return b
         + 256*g
         + 256*256*r;
}

void MatPrint(Mat* m, int pixelsize){
    bool val=0;
    int i,j,h=m->h,l=m->l;

    setcolor(getcolor(0,0,0));
    
    for(i=0 ; i<l ; i++){
        for(j=0 ; j<h ; j++){
            val=MatVal(i,j,m);
            if(val){
                PrintPixel(i,j,pixelsize);
            }
        }
    }
}


bool CaseLibre(Mat* m, couple c){
    int x=c.x,y=c.y;
    return !MatVal(x-1,y-1,m) && !MatVal(x,y-1,m) && !MatVal(x+1,y-1,m) &&
           !MatVal(x-1,y,m)   && !MatVal(x,y,m)   && !MatVal(x+1,y,m)   &&
           !MatVal(x-1,y+1,m) && !MatVal(x,y+1,m) && !MatVal(x+1,y+1,m);
}

void MatSeed(int n, Mat* m){
    int i,
        h=m->h,
        l=m->l;

    for(i=0 ; i<n ; i++){
        if(rand()%3){              // 2/3 des seeds sont mis contre les murs
            if(rand()%2){          // repartition sur les murs verticaux / horizontaux
                if(rand()%2){
                    MatSet(1,rand()%(h-2)+1,VRAI,m);
                }else{
                    MatSet(l-2,rand()%(h-2)+1,VRAI,m);
                }
            }else{
                if(rand()%2){
                    MatSet(rand()%(l-2)+1,1,VRAI,m);
                }else{
                    MatSet(rand()%(l-2)+1,h-2,VRAI,m);
                }
            }
        }else{
            MatSet(rand()%(l-2)+1,rand()%(h-2)+1,VRAI,m);
        }
    }

    MatSet(1,1,FAUX,m);        // Enlever les eventuelles seeds mises sur la case de début
    MatSet(l-2,h-2,FAUX,m);    // et de fin
}

void ConstruireCouple(Mat* m, couple c){
    MatSet(c.x,c.y,VRAI,m);
}

bool EstConstructible(Mat* m, couple c){
    int x=c.x,y=c.y,i;
    int l=m->l;
    int h=m->h;

    if(x>1 && x<l-2 && y>1 && y<h-2){                 // Ne pas faire de tests hors du tableau
        bool tab[3][3];
        for(i=0 ; i<9 ; i++)
            tab[i%3][i/3]=MatVal(i%3+x-1,i/3+y-1,m);  // Recuperation des 9 cases environnantes

        if(tab[1][0])
            if(!(tab[0][1] || tab[0][2] || tab[1][2] || tab[2][2] || tab[2][1])) return 1;
        if(tab[0][1])
            if(!(tab[1][0] || tab[2][0] || tab[2][1] || tab[2][2] || tab[1][2])) return 1;
        if(tab[1][2])
            if(!(tab[0][1] || tab[0][0] || tab[1][0] || tab[2][0] || tab[2][1])) return 1;
        if(tab[2][1])
            if(!(tab[1][0] || tab[0][0] || tab[0][1] || tab[0][2] || tab[1][2])) return 1;
    }
    return 0;
}



Ens EnsConstructible(Mat* m, char options, int pixelsize){
    if(options) setcolor(getcolor(0,255,0));

    int i,j;
    couple ctemp = {0,0};
    Ens e;
    e=EnsAlloc();
    for(i=0 ; i<m->h ; i++){
        for(j=0 ; j<m->l ; j++){
            ctemp.x=j;
            ctemp.y=i;
            if (EstConstructible(m,ctemp) && !MatVal(ctemp.x,ctemp.y,m)){
                EnsAjoute(e,ctemp);
                if(options) PrintPixel(ctemp.x,ctemp.y,pixelsize);
            }
        }
    }
    return e;
}

Ens EnsUpdate(Mat* m, Ens e, couple c, char options, int pixelsize){
    int i,j;
    couple ctemp=c;
    for(i=-1 ; i<2 ; i++){
        for(j=-1 ; j<2 ; j++){
            ctemp.x=c.x+i;
            ctemp.y=c.y+j;
            if (EstConstructible(m,ctemp) && !MatVal(ctemp.x,ctemp.y,m)){
                EnsAjoute(e,ctemp);
                if(options==2){
                    setcolor(getcolor(200,0,0));
                    PrintPixel(ctemp.x,ctemp.y,pixelsize);
                }
            }else{
                EnsSuppr(e,ctemp);
                if(options){
                    setcolor(getcolor(200,255,200));
                    PrintPixel(ctemp.x,ctemp.y,pixelsize);
                }
            }
        }
    }
    return e;
}

void MatLaby(Mat *m, char options, int pixelsize){
    Ens cons = EnsAlloc();
    couple ctemp = {0,0};
    cons = EnsConstructible(m,0,0);
    clock_t lastrefresh = clock();
    while(!EnsEstVide(cons)){
        ctemp = EnsTirage(cons);
        ConstruireCouple(m,ctemp);
        cons = EnsUpdate(m,cons,ctemp,options,pixelsize);
        if(clock() > lastrefresh+CLOCKS_PER_SEC/10 && options){
            MatPrint(m,pixelsize);
            refresh();
            flushgraph();
            lastrefresh=clock();
        }
    }
    if(options){
        MatPrint(m,pixelsize);
        refresh();
        flushgraph();
    }
}


Ens ResoudreLaby(Mat *m,char options, int pixelsize){
    int h=m->h;
    int l=m->l;
    int i,j,resolu=0,modif=1;
    char **tab = malloc(l*sizeof(char*));
    for(i=0 ; i<l ; i++) tab[i] = malloc(h*sizeof(char));

    for(i=0 ; i<l ; i++){
        for(j=0 ; j<h ; j++){
            if(MatVal(i,j,m)) tab[i][j]=-1;
            else              tab[i][j]=0;
        }
    }
    tab[1][1]=5;
    tab[l-2][h-2]=6;
    
    if(options){
        setcolor(getcolor(128,128,128));
        PrintPixel(1,1,pixelsize);
    }

    while(!resolu && modif){
        modif=0;
        for(j=0 ; j<h ; j++){
            for(i=0 ; i<l ; i++){
                if(tab[i][j]>0 && tab[i][j]<6){
                    if(tab[i+1][j]==0){
                        if(options) PrintPixel(i+1,j,pixelsize);
                        tab[i+1][j]=4;
                        modif=1;
                    }
                    if(tab[i-1][j]==0){
                        if(options) PrintPixel(i-1,j,pixelsize);
                        tab[i-1][j]=2;
                        modif=1;
                    }
                    if(tab[i][j+1]==0){
                        if(options) PrintPixel(i,j+1,pixelsize);
                        tab[i][j+1]=1;
                        modif=1;
                    }
                    if(tab[i][j-1]==0){
                        if(options) PrintPixel(i,j-1,pixelsize);
                        tab[i][j-1]=3;
                        modif=1;
                    }
                    if(tab[i+1][j]==6){
                        tab[i+1][j]=4;
                        resolu=1;
                    }
                    if(tab[i-1][j]==6){
                        tab[i-1][j]=2;
                        resolu=1;
                    }
                    if(tab[i][j+1]==6){
                        tab[i][j+1]=1;
                        resolu=1;
                    }
                    if(tab[i][j-1]==6){
                        tab[i+1][j]=3;
                        resolu=1;
                    }
                }
            }
        }
        if(options){
            refresh();
            flushgraph();
        }
    }
    i=l-2;
    j=h-2;

    Ens sol = EnsAlloc();
    couple c;
    
    if(resolu){
        while(tab[i][j]!=5){
            c.x=i;
            c.y=j;
            EnsAjoute(sol,c);
            if(tab[i][j]==1){
                j--;
            }else if(tab[i][j]==2){
                i++;
            }else if(tab[i][j]==3){
                j++;
            }else if(tab[i][j]==4){
                i--;
            }
        }
        c.x=i;
        c.y=j;
        EnsAjoute(sol,c);
    }
    return sol;
}
